package com.lcm.weam.entity.algo;

import Jama.Matrix;
import com.lcm.weam.util.MarkovUtil;
import lombok.Getter;

import java.util.ArrayList;
import java.util.List;

//默认输入最大步长（阶数）为 5
@Getter
public class Markov {
    //私有属性在类初始化是生成，生成后不改变
    private double[] data; //数据
    private final int n; //状态数
    private double mean; //均值
    private double meanSquare; //均方差
    private double[] limits; //分级 n - 1
    private List<Matrix> matrices; //各阶的转移概率矩阵 长度5 矩阵n × n
    private double[] dataStates; //数据类型 等于data.lenth
    private double[] rk; //各阶自相关系数 长度5
    private double[] weights; //各阶权重 长度5
    private Matrix valueMatrix; //预测年的转移概率矩阵p 矩阵5 × n
    private double value; //预测值

    public Markov(double[] data, int n) {
        this.n = n;
        MarkovUtil.setN(n);
        this.data = data;
        this.mean = MarkovUtil.mean(data);
        this.meanSquare = MarkovUtil.meanSquare(data, mean);
        this.limits = MarkovUtil.getLimits(mean, meanSquare);
        this.matrices = doFiveMatrix();
        this.dataStates = doDataStates();
        this.rk = doRk();
        this.weights = doWeight();
        this.valueMatrix = doValueMatrix();
        this.value = doValue();
    }

    //验证各阶（共5阶），返回验证结果
    public double[] doVerify(){
        double[] res = new double[5]; //5 表示5阶（步数）
        double[] dataState = MarkovUtil.getDataState(data, limits);
        for (int i = 0; i < 5; i++) {
            double[][] transferMatrix = MarkovUtil.getTransferMatrix(dataState, i + 1);
            res[i] = MarkovUtil.isUseful(transferMatrix);
        }
        return res;
    }

    //获取各阶（共5阶）转移概率矩阵
    private List<Matrix> doFiveMatrix(){
        double[] dataState = MarkovUtil.getDataState(data, limits);
        List<Matrix> list = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Matrix matrix = new Matrix(MarkovUtil.getPMatrix(MarkovUtil.getTransferMatrix(dataState, i + 1)));
            list.add(matrix);
        }
        return list;
    }

    //各步长的自相关系数
    private double[] doRk(){
        double[] rk = new double[5];
        for (int i = 0; i < rk.length; i++) {
            rk[i] = MarkovUtil.getRk(data, mean, i+1);
        }
        return rk;
    }

    //各个状态的权重
    private double[] doWeight(){
        return MarkovUtil.getWeight(rk);
    }

    private double[] doDataStates(){
        return MarkovUtil.getDataState(data, limits);
    }

    //结果转移矩阵 valueMatrix 5*n
    private Matrix doValueMatrix(){
        int m = data.length;
        double[][] p = new double[5][n];
        for (int i = 0; i < 5; i++) {
            for (int j = 0; j < n; j++) {
                p[i][j] = matrices.get(i).get((int)dataStates[m - i - 1] - 1,j);
            }
        }
        return new Matrix(p);
    }

    //结果转移矩阵加权 长度n
    private double doValue(){
        double[] p = new double[n];
        for (int i = 0; i < n; i++) {
            double sum = 0.0;
            for (int j = 0; j < 5; j++) {
                sum += valueMatrix.get(j,i) * weights[j];
            }
            p[i] = sum;
        }
        return MarkovUtil.getValue(p, limits, data);
    }

    //改变数据同时改变其他值
    public void setData(double[] data) {
        this.data = data;
        this.mean = MarkovUtil.mean(data);
        this.meanSquare = MarkovUtil.meanSquare(data, mean);
        this.limits = MarkovUtil.getLimits(mean, meanSquare);
        this.matrices = doFiveMatrix();
        this.dataStates = doDataStates();
        this.rk = doRk();
        this.weights = doWeight();
        this.valueMatrix = doValueMatrix();
        this.value = doValue();
    }

}
